﻿using JMBox.Util;
using JMBox.Utils.Log;
using JMLibrary.Codes;
using JMLibrary.Hooks;
using OpenCvSharp;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using static JMBox.Config.R;

namespace JMBox.Utils
{
    public class ImgPoiTool
    {
        public static MouseHook mouseHook = new MouseHook();

        public static UserLocation LocateUserAndTargetImg(string screenImgPath, string imgPath, double screenProportion, bool needDrawRect)
        {
            double shortestDistance = double.MaxValue;
            OpenCvSharp.Point closestMatch = new OpenCvSharp.Point();
            double closestScore = 0;
            System.Drawing.Size tempSize;
            Location user;


            using (Mat srcImage = Cv2.ImRead(screenImgPath, ImreadModes.AnyColor))
            using (Mat tempImage = Cv2.ImRead(imgPath, ImreadModes.AnyColor))
            {
                tempSize = new System.Drawing.Size(tempImage.Width, tempImage.Height); // 获取模板图像尺寸
                using (Mat result = new Mat())
                {
                    Cv2.MatchTemplate(srcImage, tempImage, result, TemplateMatchModes.CCoeffNormed);

                    double minVal, maxVal;
                    OpenCvSharp.Point minLoc, maxLoc;
                    double threshold = GlobalConfig.MatchThreshold; // 阈值

                    // 计算 srcImage 的中心点
                    System.Drawing.Point srcCenter = new System.Drawing.Point(srcImage.Width / 2 + GlobalConfig.MIME_OBJ_OFFSET_X, srcImage.Height / 2 + GlobalConfig.MIME_OBJ_OFFSET_Y);
                    user = new Location((int)(srcCenter.X * screenProportion), (int)(srcCenter.Y * screenProportion), 0);

                    while (true)
                    {
                        Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);
                        Logger.Default.Info("### maxVal匹配度:" + maxVal);
                        if (maxVal >= threshold)
                        {
                            // 计算匹配区域的中心位置
                            System.Drawing.Point matchCenter = new System.Drawing.Point(maxLoc.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, maxLoc.Y + (tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);

                            // 计算距离
                            double distance = Math.Sqrt(Math.Pow(matchCenter.X - srcCenter.X, 2) + Math.Pow(matchCenter.Y - srcCenter.Y, 2));

                            if (distance < shortestDistance)
                            {
                                shortestDistance = distance;
                                closestMatch = maxLoc;
                                closestScore = maxVal;
                            }

                            if (needDrawRect)
                            {
                                // 标记所有匹配区域为绿色框
                                DrawSimplePatternedRectangle(srcImage, maxLoc, new OpenCvSharp.Point(maxLoc.X + tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X, maxLoc.Y + tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y), Scalar.Blue, 2, Scalar.Blue, 5);
                                // 在匹配中心和源图像中心之间画线
                                Cv2.Line(srcImage, new OpenCvSharp.Point(srcCenter.X, srcCenter.Y), new OpenCvSharp.Point(matchCenter.X, matchCenter.Y), Scalar.Blue, 1);
                                // 在线的中部标注长度
                                System.Drawing.Point midPoint = new System.Drawing.Point((srcCenter.X + matchCenter.X) / 2, (srcCenter.Y + matchCenter.Y) / 2);
                                string lengthText = $"Length: {distance:N2}";
                                Cv2.PutText(srcImage, lengthText, new OpenCvSharp.Point(midPoint.X, midPoint.Y), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
                            }

                            // 更新result矩阵，排除已找到的匹配项
                            Cv2.FloodFill(result, maxLoc, new Scalar(0), out OpenCvSharp.Rect rect, new Scalar(0), new Scalar(0), FloodFillFlags.FixedRange);
                        }
                        else
                        {
                            break;
                        }
                    }

                    // 标记最短距离的匹配区域为红色框
                    if (shortestDistance < double.MaxValue)
                    {
                        if (true)
                        {
                            Cv2.Rectangle(srcImage, closestMatch, new OpenCvSharp.Point(closestMatch.X + tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X, closestMatch.Y + tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y), Scalar.Red, 2);

                            // 计算最短距离匹配区域的中心点
                            System.Drawing.Point closestCenter = new System.Drawing.Point(closestMatch.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, closestMatch.Y + (tempSize.Height + +GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);

                            // 在两个中心点之间画线
                            Cv2.Line(srcImage, new OpenCvSharp.Point(srcCenter.X, srcCenter.Y), new OpenCvSharp.Point(closestCenter.X, closestCenter.Y), Scalar.Red, 2);
                        }
                        srcImage.SaveImage(screenImgPath);
                    }
                }
            }

            if (shortestDistance < double.MaxValue)
            {
                System.Drawing.Point closestCenter = new System.Drawing.Point(closestMatch.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, closestMatch.Y + (tempSize.Height + +GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);

               
                Location target = new Location((int)(closestCenter.X * screenProportion), (int)(closestCenter.Y * screenProportion), closestScore);

                UserLocation userLocation = new UserLocation();
                userLocation.user = user;
                userLocation.target = target;
                userLocation.distance_x = user.X - target.X;
                userLocation.distance_y = user.Y - target.Y;

                return userLocation;
            }
            else
            {
                return new UserLocation();
            }
        }

        public static void MoveTargetPoi(string screenImgPath, string imgPath, double screenProportion)
        {
            UserLocation userLocation = LocateUserAndTargetImg(screenImgPath, imgPath, screenProportion,false);
            if (userLocation.target != null && userLocation.target.X != -1)
            {
                //如果u在上面。执行s
                if (userLocation.distance_y < (0 - GlobalConfig.User_Move_Offset))
                {
                    MoveExecute(Keys.S, userLocation.distance_y, GlobalConfig.User_Move_One_Step);
                }
                //如果u在下面，执行w
                if (userLocation.distance_y > GlobalConfig.User_Move_Offset)
                {
                    MoveExecute(Keys.W, userLocation.distance_y, GlobalConfig.User_Move_One_Step);
                }
                //如果u在右面。执行a
                if (userLocation.distance_x > GlobalConfig.User_Move_Offset)
                {
                    MoveExecute(Keys.A, userLocation.distance_x, GlobalConfig.User_Move_One_Step);
                }

                //如果u在左面。执行d
                if (userLocation.distance_x < (0 - GlobalConfig.User_Move_Offset))
                {
                    MoveExecute(Keys.D, userLocation.distance_x, GlobalConfig.User_Move_One_Step);
                }
            }
        }

        public static void MoveExecute(Keys key, int distance, int oneStep)
        {
            int count = Math.Abs(distance) / oneStep;
            Logger.Default.Info("方向: "+key+",count:" + count);

            for (int i = 0; i < count - 1; i++)
            {
                Contact.MainUI.GetPressKey().KeyDown(key);
                Thread.Sleep(10);
                Contact.MainUI.GetPressKey().KeyUp(key);
            }
        }


        /// <summary>
        /// 获取批图图片的坐标
        /// </summary>
        /// <param name="screenPath"></param>
        /// <param name="imgPath"></param>
        /// <returns></returns>
        public static Location LocateOnTargetImgNearest(string screenImgPath, string imgPath, double screenProportion, bool needDrawRect)
        {
            double shortestDistance = double.MaxValue;
            OpenCvSharp.Point closestMatch = new OpenCvSharp.Point();
            double closestScore = 0;
            System.Drawing.Size tempSize;
            Location srcCenterPoi;

            using (Mat srcImage = Cv2.ImRead(screenImgPath, ImreadModes.AnyColor))
            using (Mat tempImage = Cv2.ImRead(imgPath, ImreadModes.AnyColor))
            {
                tempSize = new System.Drawing.Size(tempImage.Width, tempImage.Height); // 获取模板图像尺寸

                using (Mat result = new Mat())
                {
                    Cv2.MatchTemplate(srcImage, tempImage, result, TemplateMatchModes.CCoeffNormed);

                    double minVal, maxVal;
                    OpenCvSharp.Point minLoc, maxLoc;
                    double threshold = GlobalConfig.MatchThreshold; // 阈值

                    // 计算 srcImage 的中心点
                    System.Drawing.Point srcCenter = new System.Drawing.Point(srcImage.Width / 2 + GlobalConfig.MIME_OBJ_OFFSET_X, srcImage.Height / 2 + GlobalConfig.MIME_OBJ_OFFSET_Y);
                    srcCenterPoi = new Location((int)(srcCenter.X * screenProportion), (int)(srcCenter.Y * screenProportion), closestScore);
                    Logger.Default.Info("### 中心位置坐标:" + srcCenterPoi.X + "|" + srcCenterPoi.Y);

                    while (true)
                    {
                        Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);
                        Logger.Default.Info("### maxVal匹配度:" + maxVal);
                        if (maxVal >= threshold)
                        {
                            // 计算匹配区域的中心位置
                            System.Drawing.Point matchCenter = new System.Drawing.Point(maxLoc.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, maxLoc.Y + (tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);

                            // 计算距离
                            double distance = Math.Sqrt(Math.Pow(matchCenter.X - srcCenter.X, 2) + Math.Pow(matchCenter.Y - srcCenter.Y, 2));

                            if (distance < shortestDistance)
                            {
                                shortestDistance = distance;
                                closestMatch = maxLoc;
                                closestScore = maxVal;
                            }

                            if (needDrawRect)
                            {
                                // 标记所有匹配区域为绿色框
                                DrawSimplePatternedRectangle(srcImage, maxLoc, new OpenCvSharp.Point(maxLoc.X + tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X, maxLoc.Y + tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y), Scalar.Blue, 2, Scalar.Blue, 5);
                                // 在匹配中心和源图像中心之间画线
                                Cv2.Line(srcImage, new OpenCvSharp.Point(srcCenter.X, srcCenter.Y), new OpenCvSharp.Point(matchCenter.X, matchCenter.Y), Scalar.Blue, 1);
                                // 在线的中部标注长度
                                System.Drawing.Point midPoint = new System.Drawing.Point((srcCenter.X + matchCenter.X) / 2, (srcCenter.Y + matchCenter.Y) / 2);
                                string lengthText = $"Length: {distance:N2}";
                                Cv2.PutText(srcImage, lengthText, new OpenCvSharp.Point(midPoint.X, midPoint.Y), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
                            }

                            // 更新result矩阵，排除已找到的匹配项
                            Cv2.FloodFill(result, maxLoc, new Scalar(0), out OpenCvSharp.Rect rect, new Scalar(0), new Scalar(0), FloodFillFlags.FixedRange);
                        }
                        else
                        {
                            break;
                        }
                    }

                    // 标记最短距离的匹配区域为红色框
                    if (shortestDistance < double.MaxValue)
                    {
                        if (true)
                        {
                            Cv2.Rectangle(srcImage, closestMatch, new OpenCvSharp.Point(closestMatch.X + tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X, closestMatch.Y + tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y), Scalar.Red, 2);

                            // 计算最短距离匹配区域的中心点
                            System.Drawing.Point closestCenter = new System.Drawing.Point(closestMatch.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, closestMatch.Y + (tempSize.Height + +GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);

                            // 在两个中心点之间画线
                            Cv2.Line(srcImage, new OpenCvSharp.Point(srcCenter.X, srcCenter.Y), new OpenCvSharp.Point(closestCenter.X, closestCenter.Y), Scalar.Red, 2);
                        }
                        srcImage.SaveImage(screenImgPath);
                    }
                }
            }

            if (shortestDistance < double.MaxValue)
            {
                System.Drawing.Point closestCenter = new System.Drawing.Point(closestMatch.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, closestMatch.Y + (tempSize.Height + +GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);
                return new Location((int)(closestCenter.X * screenProportion), (int)(closestCenter.Y * screenProportion), closestScore);
            }
            else
            {
                // 如果没有找到匹配项，可以返回一个默认值或者错误指示
                return new Location(-1, -1, -1);
            }
        }

        /// <summary>
        /// 匹配一张图片即可
        /// </summary>
        /// <param name="screenImgPath"></param>
        /// <param name="imgPath"></param>
        /// <param name="screenProportion"></param>
        /// <param name="needDrawRect"></param>
        /// <returns></returns>
        public static Location LocateOnTargetImgSimple(string screenImgPath, string imgPath, double screenProportion, bool needDrawRect)
        {
            double closestScore = 0;
            System.Drawing.Size tempSize;
            Location srcCenterPoi;

            using (Mat srcImage = Cv2.ImRead(screenImgPath, ImreadModes.AnyColor))
            using (Mat tempImage = Cv2.ImRead(imgPath, ImreadModes.AnyColor))
            {
                tempSize = new System.Drawing.Size(tempImage.Width, tempImage.Height); // 获取模板图像尺寸

                using (Mat result = new Mat())
                {
                    Cv2.MatchTemplate(srcImage, tempImage, result, TemplateMatchModes.CCoeffNormed);

                    double minVal, maxVal;
                    OpenCvSharp.Point minLoc, maxLoc;
                    double threshold = GlobalConfig.MatchThreshold; // 阈值

                    // 计算 srcImage 的中心点
                    System.Drawing.Point srcCenter = new System.Drawing.Point(srcImage.Width / 2 + GlobalConfig.MIME_OBJ_OFFSET_X, srcImage.Height / 2 + GlobalConfig.MIME_OBJ_OFFSET_Y);
                    srcCenterPoi = new Location((int)(srcCenter.X * screenProportion), (int)(srcCenter.Y * screenProportion), closestScore);
                    Logger.Default.Info("### 中心坐标:" + srcCenterPoi.X + "|" + srcCenterPoi.Y);

                    while (true)
                    {
                        Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);
                        Logger.Default.Info("### 匹配度:" + maxVal);
                        if (maxVal >= threshold)
                        {
                            // 计算匹配区域的中心位置
                            System.Drawing.Point matchCenter = new System.Drawing.Point(maxLoc.X + (tempSize.Width + GlobalConfig.TARGET_OBJ_OFFSET_X) / 2, maxLoc.Y + (tempSize.Height + GlobalConfig.TARGET_OBJ_OFFSET_Y) / 2);
                            return new Location((int)(matchCenter.X * screenProportion), (int)(matchCenter.Y * screenProportion), maxVal);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            return new Location(-1, -1, -1);
        }


        public static void DrawSimplePatternedRectangle(Mat srcImage, OpenCvSharp.Point rectStart, OpenCvSharp.Point rectEnd, Scalar rectBorderColor, int borderThickness, Scalar lineColor, int lineSpacing)
        {
            // 绘制矩形边框
            Cv2.Rectangle(srcImage, rectStart, rectEnd, rectBorderColor, borderThickness);
        }


        public const int HORZRES = 8;
        public const int VERTRES = 10;
        public const int LOGPIXELSX = 88;
        public const int LOGPIXELSY = 90;
        public const int DESKTOPVERTRES = 117;
        public const int DESKTOPHORZRES = 118;

        [DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr ptr);
        [DllImport("gdi32.dll")]
        static extern int GetDeviceCaps(IntPtr hdc, int nIndex);// index of capability

        /// <summary>
        /// 屏幕截屏
        /// </summary>
        /// <param name="savePath"></param>
        /// <returns>返回逻辑与物理比例</returns>
        public static double CaptureScreen(string savePath)
        {
            IntPtr hdc = GetDC(IntPtr.Zero);
            int PhyW = GetDeviceCaps(hdc, DESKTOPHORZRES); //得到物理分辨率
            int PhyH = GetDeviceCaps(hdc, DESKTOPVERTRES);

            int LogicW = GetDeviceCaps(hdc, HORZRES); //得到逻辑分辨率（经过缩放后）
            int LogicH = GetDeviceCaps(hdc, VERTRES);

            Bitmap cBmp = new Bitmap(PhyW, PhyH);
            Graphics g = Graphics.FromImage(cBmp);
            g.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), new System.Drawing.Size(PhyW, PhyH));
            cBmp.Save(savePath, ImageFormat.Jpeg);
            Console.WriteLine(LogicW + "|" + PhyW);
            return (double)LogicW / (double)PhyW;
        }

        /// <summary>
        /// 自动识别最近的图片
        /// </summary>
        /// <param name="imgPath"></param>
        public static Location LocateNearest(String imgPath)
        {
            if (string.IsNullOrEmpty(imgPath))
            {
                Logger.Default.Info("LocateNearest未选择目标图片！");
                return new Location(-1, -1, -1);
            }
            double screenProportion = ImgPoiTool.CaptureScreen(Contact.ScreenImgPath);
            Location loc = ImgPoiTool.LocateOnTargetImgNearest(Contact.ScreenImgPath, imgPath, screenProportion, false);
            return loc;
        }

        public static Location LocateSimple(String imgPath)
        {
            if (string.IsNullOrEmpty(imgPath))
            {
                Logger.Default.Info("LocateSimple未选择目标图片！");
                return new Location(-1, -1, -1);
            }
            double screenProportion = ImgPoiTool.CaptureScreen(Contact.ScreenImgPath);
            Location loc = ImgPoiTool.LocateOnTargetImgSimple(Contact.ScreenImgPath, imgPath, screenProportion, false);
            Logger.Default.Info(imgPath + "定位结果:" + loc.X + "|" + loc.Y);
            return loc;
        }

        /// <summary>
        /// 自动识别目标并移动
        /// </summary>
        /// <param name="imgPath"></param>
        public static void LocateAndUserMove(String imgPath)
        {
            double screenProportion = ImgPoiTool.CaptureScreen(Contact.ScreenImgPath);
            ImgPoiTool.MoveTargetPoi(Contact.ScreenImgPath, imgPath, screenProportion);
        }

        

        /// <summary>
        /// 自动识别最近的图片并点击
        /// </summary>
        /// <param name="imgPath"></param>
        public static Location LocateNearestAndMove(String imgPath)
        {

            Location loc = LocateNearest(imgPath);

            Logger.Default.Info("坐标定位结果:" + loc.X + "|" + loc.Y);
            if (loc.X == -1)
            {
                return new Location(-1, -1, -1);
            }
            if (loc.Y == -1)
            {
                return new Location(-1, -1, -1);
            }
            MouseEvent mouseEventD = new MouseEvent(MouseEventType.MouseLeftDown, loc.X, loc.Y, 100);
            mouseHook.MouseWork(mouseEventD);
            Thread.Sleep(100);
            MouseEvent mouseEventU = new MouseEvent(MouseEventType.MouseLeftDown, loc.X, loc.Y, 100);
            mouseHook.MouseWork(mouseEventU);
            Logger.Default.Info("已经移动至坐标:" + loc.X + "|" + loc.Y);
            return loc;
        }

        public static void ClickTargetPoi(Location loc)
        {
            MouseEvent mouseEventM = new MouseEvent(MouseEventType.MouseMove, loc.X, loc.Y, 100);
            mouseHook.MouseWork(mouseEventM);

            // 模拟左键按下
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, UIntPtr.Zero);

            // 模拟左键释放
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, UIntPtr.Zero);
        }

        const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
        const uint MOUSEEVENTF_LEFTUP = 0x0004;

        [DllImport("user32.dll", SetLastError = true)]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo);

    }
}
